package com.csx.base.concurrency.aqs.reentrantlock;

import com.csx.base.concurrency.util.TimeUtil;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p> what does this class do ? </p>
 *  该案例给出的是非阻塞获取锁的案例
 *  1. boolean tryLock() 非阻塞式获取锁
 *    尝试非阻塞式获取锁,调用该方法获取锁立即返回获取结果.
 *    如果获取到了锁则返回true,反之返回false
 *  2. boolean tryLock(timeout,timeunit) 非阻塞式获取锁。
 *    根据传入的时间获取锁。如果在该时间内成功获取了锁并未被中断则返回true,否则返回false
 * <p> How does it work ?</p>
 * <p> Why does it do this ?</p>
 *
 * @author cuisongxu
 * @date 2024/12/2 周一 10:14
 */
public class ReentrantLockTryLockTest {

    private final ReentrantLock lock = new ReentrantLock();

    public void test() {

        try {
            // tryLock 获取锁成功
            System.out.println("开始测试 tryLock 获取锁成功");
            Thread thread1 = new Thread(new TryLockTask(), "thread1");
            thread1.start();
            thread1.join();
            System.out.println();

            // tryLock 获取锁失败
            System.out.println("开始测试 tryLock 获取锁失败");
            Thread thread2 = new Thread(new CustomTimeTask(3), "thread2");
            Thread thread3 = new Thread(new TryLockTask(), "thread3");
            thread2.start();
            TimeUnit.SECONDS.sleep(1);
            thread3.start();

            thread2.join();
            thread3.join();
            System.out.println();

            // tryLock(timeout) 获取锁成功
            System.out.println("开始测试 tryLock(timeout) 获取锁成功");
            Thread thread4 = new Thread(new TryLockTask(2L, TimeUnit.SECONDS), "thread4");
            thread4.start();
            thread4.join();
            System.out.println();

            // tryLock(timeout) 获取锁失败
            System.out.println("开始测试 tryLock(timeout) 获取锁失败");
            Thread thread5 = new Thread(new CustomTimeTask(3),"thread5");
            Thread thread6 = new Thread(new TryLockTask(1L, TimeUnit.SECONDS), "thread6");
            thread5.start();
            TimeUnit.SECONDS.sleep(1);
            thread6.start();

            thread5.join();
            thread6.join();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


    }

    class TryLockTask implements Runnable {

        private Long timeout;
        private TimeUnit timeUnit;

        public TryLockTask(Long timeout, TimeUnit timeUnit) {
            this.timeout = timeout;
            this.timeUnit = timeUnit;
        }

        public TryLockTask() {

        }
        @Override
        public void run() {
            try {
                // timeout 和 timeUnit 都有值时，调用 lock.tryLock(timeout, timeUnit), 否则调用 lock.tryLock()
                if(((timeout != null && timeUnit != null) && lock.tryLock(timeout, timeUnit)) || lock.tryLock()) {
                    String nowTimeStr = TimeUtil.getNowTimeStr();
                    System.out.println(nowTimeStr + " " + Thread.currentThread().getName() + "获取了锁");
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        lock.unlock();
                        nowTimeStr = TimeUtil.getNowTimeStr();
                        System.out.println(nowTimeStr + " " + Thread.currentThread().getName() + "释放了锁");
                    }
                }else {
                    // 获取锁失败
                    String nowTimeStr = TimeUtil.getNowTimeStr();
                    System.out.println(nowTimeStr + " " + Thread.currentThread().getName() + "获取锁失败");
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    class CustomTimeTask implements Runnable {

        private final int seconds;

        public CustomTimeTask(int seconds) {
            this.seconds = seconds;
        }
        @Override
        public void run() {
            lock.lock();
            try {
                // 休眠指定时间，模拟任务耗时
                TimeUnit.SECONDS.sleep(seconds);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
}
